﻿Option Explicit On
'*******************************************************************
' Program: pkgVisio
' Author: Albert E Edlund
' Date:
'
' Purpose:
' Working with office object XML
'
'*******************************************************************


#Region " imports "

Imports System
Imports System.Object
Imports System.IO
Imports System.IO.TextReader
' need to reference windowsbase in .net
Imports System.IO.Packaging

' need for dbconnectionstringbuilder used in clsConnections
Imports System.Data.Common

Imports System.Windows
Imports System.Windows.Forms
Imports System.Text.StringBuilder

Imports Microsoft.VisualBasic

Imports System.Text
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.ObjectModel

Imports System.Xml
Imports System.Linq
Imports System.Linq.Enumerable
Imports System.Windows.Input

Imports System.Xml.Serialization
Imports System.Xml.Linq
Imports System.Xml.XPath

Imports ADODB
Imports System.Data
Imports System.Data.OleDb
Imports System.Data.Sql


Imports Microsoft.Practices.EnterpriseLibrary.Common
Imports Microsoft.Practices.EnterpriseLibrary.ExceptionHandling
Imports Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging


' visio v15 does not use a xName prefix which may put it into conflict with other open office apps
Imports <xmlns="http://schemas.microsoft.com/office/visio/2012/main">
Imports <xmlns:rs="urn:schemas-microsoft-com:rowset">

' generic namespace for office open xml, used in all of them
Imports <xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">

Imports pkgVisio.clsVisPackage
Imports pkgVisio.clsStructures


#End Region


'**********************************************************************************
'
' holds attributes and elements for each of the datarecordsets
' holds the datacolumns, primarykeys, and rowmaps for each of the datarecordsets
' it also holds the pointer for the recordset files
'
'**********************************************************************************
'
Public Class clsRecordsets


#Region " Properties and Declarations "


    Public Structure itemRecordset
        Public rsId As Long
        Public rsConnId As Long
        Public rsName As String
        Public rsCommand As String
        Public rsRsc As String
        Public rsFile As String

        Public Sub New _
            (ByVal rsId As Long, _
             ByVal rsConnId As Long, _
             ByVal rsName As String, _
             ByVal rsCommand As String, _
             ByVal rsRsc As String, _
             ByVal rsFile As String)

            Me.rsId = rsId
            Me.rsConnId = rsConnId
            Me.rsName = rsName
            Me.rsCommand = rsCommand
            Me.rsRsc = rsRsc
            Me.rsFile = rsFile

        End Sub

    End Structure


    '
    '
    '
    Private m_colRecordsets As Collection(Of itemRecordset)
    Public Property colRecordsets As Collection(Of itemRecordset)
        Get
            If m_colRecordsets Is Nothing Then
                m_colRecordsets = New Collection(Of itemRecordset)
            End If
            colRecordsets = m_colRecordsets
        End Get
        Set(value As Collection(Of itemRecordset))
            m_colRecordsets = value
        End Set
    End Property


    '
    ' pkgpartInfo is the collection of content and file pointers in the package
    '
    Private m_colPkgPartInfo As Collection(Of pkgpartInfo)
    Public Property colPkgPartInfo As Collection(Of pkgpartInfo)
        Get
            colPkgPartInfo = Me.m_colPkgPartInfo
        End Get
        Set(value As Collection(Of pkgpartInfo))
            If (value Is Nothing) Then
                Throw New System.ArgumentNullException("Value", _
                    "colPkgPartsInfo is Null.")
            End If
            Me.m_colPkgPartInfo = value
        End Set
    End Property


    '
    '
    '
    Public m_xDoc As XDocument
    Public Property xDoc As XDocument
        Get
            Return Me.m_xDoc
        End Get
        Set(value As XDocument)
            If (value Is Nothing) Then
                Throw New System.ArgumentNullException("Value", _
                    "xDoc is Null.")
            End If
            Me.m_xDoc = value
        End Set
    End Property

    '
    '
    '
    Public m_visPackage As clsVisPackage
    Public Property visPackage As clsVisPackage
        Get
            visPackage = Me.m_visPackage
        End Get
        Set(value As clsVisPackage)
            If (value Is Nothing) Then
                Throw New System.ArgumentNullException("Value", _
                    "visPackage is Null.")
            End If
            Me.m_visPackage = value
        End Set
    End Property



#End Region

    '
    ' pass in a listview control and load it with the datarecordsets
    '
    Public Sub loadDataRecordSets _
                (ByRef lvControl As ListView)

        Dim lngRsId As Long = -1
        Dim lngRsConnId As Long = -1
        Dim strRsName As String = ""
        Dim strRsCommand As String = ""
        Dim strRsRsc As String = ""
        Dim strRsFile As String
        Dim lvItem As ListViewItem
        m_colRecordsets.Clear()

        Try

            If lvControl IsNot Nothing Then
                lvControl.Items.Clear()
                lvControl.Columns.Clear()
                lvControl.View = View.Details
                lvControl.AllowColumnReorder = True
                lvControl.FullRowSelect = True
                lvControl.Columns.Add("Name", 100, HorizontalAlignment.Left)
                lvControl.Columns.Add("Id", 40, HorizontalAlignment.Right)
                lvControl.Columns.Add("ConnId", 40, HorizontalAlignment.Right)
                lvControl.Columns.Add("Cmd", 100, HorizontalAlignment.Left)
                lvControl.Columns.Add("Rsc", 50, HorizontalAlignment.Left)
                lvControl.Columns.Add("File", 150, HorizontalAlignment.Left)
            End If

            ' first check for a v2007/v12 implementation
            Dim qryRecordsets = Me.xDoc...<DataRecordSet>
            Dim intRecordsets As Integer = qryRecordsets.Count

            For Each recordset In qryRecordsets

                lngRsId = -1
                lngRsConnId = -1
                strRsName = "NoName"
                strRsFile = "NoFile"

                Dim listOfAttributes As IEnumerable(Of XAttribute) = _
                    From att In recordset.Attributes() _
                    Select att

                For Each att As XAttribute In listOfAttributes
                    ' Console.WriteLine("{0}={1}", att.Name.LocalName, att.Value)
                    Select Case LCase(att.Name.LocalName)
                        Case "id"
                            lngRsId = CLng(att.Value)
                        Case "name"
                            ' get the recordset name
                            strRsName = CStr(att.Value)
                        Case "connectionid"
                            lngRsConnId = CLng(att.Value)
                        Case "command"
                            strRsCommand = CStr(att.Value)
                    End Select
                Next att


                Dim listofElements As IEnumerable(Of XElement) = _
                    From elem In recordset.Elements() _
                    Select elem
                For Each elem As XElement In listofElements
                    Select Case LCase(elem.Name.LocalName)
                        Case "rel"
                            strRsRsc = CStr(elem.@r:id)
                    End Select
                Next elem

                ' go find the associated file

                For Each PkgPart In Me.colPkgPartInfo
                    If PkgPart.pkgpartContentType = clsVisPackage.contXmlRecordset _
                        And PkgPart.pkgpartResourceId = strRsRsc Then
                        strRsFile = PkgPart.pkgpartPath
                        Exit For
                    End If
                Next PkgPart

                Dim itemRS As itemRecordset = New itemRecordset _
                           (lngRsId, lngRsConnId, strRsName, strRsCommand, strRsRsc, strRsFile)
                colRecordsets.Add(itemRS)

                If lvControl IsNot Nothing Then
                    lvItem = New ListViewItem(strRsName)
                    lvItem.SubItems.Add(CStr(lngRsId))
                    lvItem.SubItems.Add(CStr(lngRsConnId))
                    lvItem.SubItems.Add(strRsCommand)
                    lvItem.SubItems.Add(strRsRsc)
                    lvItem.SubItems.Add(strRsFile)

                    ' add it to the listview on the data page
                    lvControl.Items.Add(lvItem)
                End If ' test for lvcontrol valid
            Next recordset


        Catch errXml As XmlException
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(errXml, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        Catch err As Exception
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(err, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        End Try

    End Sub



#Region " data columns defined in datarecordset xelement within datarecordsets "


    '
    ' have to manually enumerate the property types because we are not importing
    ' the visio libraries
    '
    Private Enum DataType
        visPropTypeNumber = 2
        visPropTypeListFix = 1
        visPropTypeListVar = 4
        visPropTypeDate = 5
        visPropTypeCurrency = 7
        visPropTypeDuration = 6
        VisPropTypeString = 0
        visPropTypeBool = 3
    End Enum


    '
    ' read v2007 schema DataColumns query source is datacolumnset
    '
    Public Sub loadDataColumnListView _
        (ByVal shapeSource As XElement, _
         ByRef lvControl As ListView)

        Try


            Dim qryDataColumn = shapeSource...<DataColumn>
            Dim intDataColumn As Integer = qryDataColumn.Count

            Dim lvItem As ListViewItem

            If lvControl IsNot Nothing Then
                lvControl.Items.Clear()
                lvControl.Columns.Clear()
                lvControl.View = View.Details
                lvControl.AllowColumnReorder = True
                lvControl.FullRowSelect = True
                lvControl.Columns.Add("NameId", 200, HorizontalAlignment.Left)
                lvControl.Columns.Add("Name", 200, HorizontalAlignment.Left)
                lvControl.Columns.Add("Label", 100, HorizontalAlignment.Left)
                lvControl.Columns.Add("DataType", 80, HorizontalAlignment.Left)
                lvControl.Columns.Add("DispOrd", 40, HorizontalAlignment.Right)
            End If ' test for lvcontrol

            For Each rsdataColumn In qryDataColumn

                Dim strNameId As String = ""
                Dim strName As String = ""
                Dim strLabel As String = ""
                ' default datatype is string
                Dim strDataType As String = "string"
                Dim strDisplayOrder As String = ""

                Dim listOfAttributes As IEnumerable(Of XAttribute) = _
                    From att In rsdataColumn.Attributes() _
                    Select att
                For Each att As XAttribute In listOfAttributes
                    ' Console.WriteLine("Column {0}={1}", att.Name.LocalName, att.Value)
                    Select Case LCase(att.Name.LocalName)
                        Case "columnnameid"
                            strNameId = att.Value
                        Case "name"
                            strName = CStr(att.Value)
                        Case "label"
                            strLabel = CStr(att.Value)
                        Case "datatype"
                            strDataType = DataTypeToStr(CInt(att.Value))
                        Case "displayorder"
                            strDisplayOrder = CStr(att.Value)
                    End Select
                Next att

                If lvControl IsNot Nothing Then
                    ' add it to the listview control
                    lvItem = New ListViewItem(strNameId)
                    lvItem.SubItems.Add(strName)
                    lvItem.SubItems.Add(strLabel)
                    lvItem.SubItems.Add(strDataType)
                    lvItem.SubItems.Add(strDisplayOrder)

                    ' add it to the listview on the data page
                    lvControl.Items.Add(lvItem)
                End If

            Next rsdataColumn

        Catch errXml As XmlException
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(errXml, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        Catch err As Exception
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(err, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        End Try

    End Sub

    '
    '
    '
    Private Function DataTypeToStr(ByVal intDataType As Integer) As String

        Dim strDataType As String = ""

        If intDataType = DataType.visPropTypeBool Then
            strDataType = "bool"
        ElseIf intDataType = DataType.visPropTypeCurrency Then
            strDataType = "currency"
        ElseIf intDataType = DataType.visPropTypeDate Then
            strDataType = "date"
        ElseIf intDataType = DataType.visPropTypeDuration Then
            strDataType = "duration"
        ElseIf intDataType = DataType.visPropTypeListFix Then
            strDataType = "listfix"
        ElseIf intDataType = DataType.visPropTypeListVar Then
            strDataType = "listvar"
        ElseIf intDataType = DataType.visPropTypeNumber Then
            strDataType = "number"
        ElseIf intDataType = DataType.VisPropTypeString Then
            strDataType = "string"
        Else
            strDataType = "???"
        End If

        DataTypeToStr = strDataType

    End Function


#End Region


#Region " row map data for datarecordset xelement within datarecordsets  "


    '
    ' read v2007 schema rowmap query source is datarecordset xelement within
    ' datarecordsets file
    '
    Public Sub loadRowMapListView _
        (ByVal shpSource As XElement, _
         ByRef lvControl As ListView)

        Try

            Dim currPageShape As stcPageShape = New stcPageShape
            Dim lvItem As ListViewItem


            Dim qryRowMap = shpSource...<RowMap>
            Dim intRowMap As Integer = qryRowMap.Count

            If lvControl IsNot Nothing Then
                lvControl.Items.Clear()
                lvControl.Columns.Clear()
                lvControl.View = View.Details
                lvControl.AllowColumnReorder = True
                lvControl.FullRowSelect = True
                lvControl.Columns.Add("RowId", 40, HorizontalAlignment.Right)
                lvControl.Columns.Add("PageId", 40, HorizontalAlignment.Right)
                lvControl.Columns.Add("PageName", 100, HorizontalAlignment.Left)
                lvControl.Columns.Add("ShapeId", 40, HorizontalAlignment.Right)
                lvControl.Columns.Add("ShapeNameU", 100, HorizontalAlignment.Left)
            End If ' test for lvcontrol



            For Each rsdataRowMap In qryRowMap

                Dim strRowId As String = "-1"
                Dim strPageId As String = "-1"
                Dim strPageNameU As String = "NoPgNameU"
                Dim strShapeId As String = "-1"
                Dim strShapeNameU As String = "NoShpNameU"

                Dim listOfAttributes As IEnumerable(Of XAttribute) = _
                    From att In rsdataRowMap.Attributes() _
                    Select att
                For Each att As XAttribute In listOfAttributes
                    ' Console.WriteLine("{0}={1}", att.Name.LocalName, att.Value)
                    Select Case LCase(att.Name.LocalName)
                        Case "rowid"
                            strRowId = CStr(att.Value)
                        Case "pageid"
                            strPageId = CStr(att.Value)
                        Case "shapeid"
                            strShapeId = CStr(att.Value)
                    End Select
                Next att

                With currPageShape
                    .psPage = CLng(strPageId)
                    .psShape = CLng(strShapeId)
                End With

                If Me.visPackage.dictPagesID.ContainsKey(CLng(strPageId)) = True Then
                    strPageNameU = Me.visPackage.dictPagesID(CLng(strPageId)).pgNameU
                End If

                If Me.visPackage.dictPageShape.ContainsKey(currPageShape) = True Then
                    strShapeNameU = Me.visPackage.dictPageShape(currPageShape).strShpNameU.ToString
                Else
                    strShapeNameU = "ShapeNotFound"
                End If

                If lvControl IsNot Nothing Then
                    lvItem = New ListViewItem(strRowId)
                    lvItem.SubItems.Add(strPageId)
                    lvItem.SubItems.Add(strPageNameU)
                    lvItem.SubItems.Add(strShapeId)
                    lvItem.SubItems.Add(strShapeNameU)

                    ' add it to the listview on the data page
                    lvControl.Items.Add(lvItem)
                End If

            Next rsdataRowMap

        Catch errXml As XmlException
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(errXml, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        Catch err As Exception
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(err, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        End Try

    End Sub




#End Region



    '
    '
    '
    Public Sub New()

        Me.m_colPkgPartInfo = Nothing
        Me.colPkgPartInfo = New Collection(Of pkgpartInfo)

        Me.m_colRecordsets = Nothing
        Me.colRecordsets = New Collection(Of itemRecordset)

        Me.m_xDoc = Nothing
        Me.xDoc = New XDocument


    End Sub



    Protected Overrides Sub Finalize()

        If Me.m_colPkgPartInfo IsNot Nothing Then
            Me.m_colPkgPartInfo = Nothing
        End If
        If Me.m_colRecordsets IsNot Nothing Then
            Me.m_colRecordsets = Nothing
        End If
        If Me.m_xDoc IsNot Nothing Then
            Me.m_xDoc = Nothing
        End If

        MyBase.Finalize()
    End Sub


End Class
